import requests
from flask import current_app, jsonify, g

from app import redisclientAccount
from app.libs.enums import ClientTypeEnum
from app.libs.error_code import AuthFailed, Success
from app.libs.qrcode import gzh_qrcode
from app.libs.redprint import Redprint
from app.libs.tools import generate_random_name
from app.models.base import db
from app.models.order_info import order_info
from app.models.user import User
from app.validators.user import ClientForm, TokenForm, WxClientForm, UpdateUnionIdForm, UpdateGzhOpenIdForm, \
    CurrentSceneIdForm, UpdateGzhOpenIdAndUnlockForm
from itsdangerous import TimedJSONWebSignatureSerializer as Serializer, SignatureExpired, \
    BadSignature

api = Redprint('token')


@api.route('', methods=['POST'])
def get_token():
    form = ClientForm().validate_for_api()
    promise = {
        ClientTypeEnum.USER_MINA: User.verify_by_wxpro,
        ClientTypeEnum.USER_SCAN: User.verify_by_scan,
    }
    identity = promise[ClientTypeEnum(form.type.data)](
        form.account.data,
        form.password.data,
        form.wx_open_id.data,
        form.wx_union_id.data,
        form.scene.data
    )
    expiration = current_app.config['TOKEN_EXPIRATION']
    token = generate_auth_token(identity['uid'],
                                form.type.data,
                                identity['scope'],
                                expiration)
    if form.type.data.value in [104, 103, 200, 201, 202, 203, 301]:
        t = {
            'error_code': 0,
            'token': token.decode('ascii'),
            'uid': identity['uid']
        }
    else:
        t = {
            'error_code': 0,
            'token': token.decode('ascii'),
        }
    return jsonify(t), 201


@api.route('/updategzhopenid', methods=['GET', 'POST'])
def getUnionid():
    form = UpdateGzhOpenIdForm().validate_for_api()
    user = User.query.filter_by(union_id=form.unionid.data).first()
    with db.auto_commit():
        if not user:
            user_model = User()
            user_model.gzh_open_id = form.gzh_open_id.data
            user_model.union_id = form.unionid.data
            user_model.role_id = 5
            user_model.nickname = generate_random_name()
            if form.writer.data == 1:
                user_model.free_chars = -1
            db.session.add(user_model)
        else:
            User.query.filter_by(union_id=form.unionid.data).update({
                'gzh_open_id': form.gzh_open_id.data
            })
            if form.writer.data == 1:
                User.query.filter_by(union_id=form.unionid.data).update({
                    'free_chars': -1
                })
    return Success()


@api.route('/updategzhopenidandunlockai', methods=['GET', 'POST'])
def getUnionidandunlockai():
    form = UpdateGzhOpenIdAndUnlockForm().validate_for_api()
    user = User.query.filter_by(union_id=form.unionid.data).first()
    with db.auto_commit():
        if not user:
            user_model = User()
            user_model.gzh_open_id = form.gzh_open_id.data
            user_model.union_id = form.unionid.data
            user_model.role_id = 5
            user_model.nickname = generate_random_name()
            db.session.add(user_model)
        else:
            User.query.filter_by(union_id=form.unionid.data).update({
                'gzh_open_id': form.gzh_open_id.data
            })
        order_info.query.filter_by(order_number=form.order_number.data).update({
            'ai_lock': 0
        })
    return Success()


@api.route('/qrcode_ticket', methods=['GET', 'POST'])
def qrcode_ticket():
    form = CurrentSceneIdForm().validate_for_api()
    qr_model = gzh_qrcode()
    redisclientAccount.setSceneId(form.currentSceneId.data, '', 120)
    ticket = qr_model.qrcode_ticket(form.currentSceneId.data)
    return jsonify({
        'ticket': ticket
    })


@api.route('/check_qr_status', methods=['GET', 'POST'])
def qr_status():
    form = CurrentSceneIdForm().validate_for_api()
    unionId = redisclientAccount.getSceneId(form.currentSceneId.data)
    if unionId is None:
        return jsonify({
            'login': False,
            'expire': True
        })
    if unionId == '':
        return jsonify({
            'login': False,
            'expire': False
        })
    redisclientAccount.client.delete(form.currentSceneId.data)
    return jsonify({
        'login': True,
        'unionid': unionId,
        'expire': False
    })


@api.route('/secret', methods=['POST'])
def get_token_info():
    """获取令牌信息"""
    form = TokenForm().validate_for_api()
    s = Serializer(current_app.config['SECRET_KEY'])
    try:
        data = s.loads(form.token.data, return_header=True)
    except SignatureExpired:
        raise AuthFailed(msg='token is expired', error_code=1003)
    except BadSignature:
        raise AuthFailed(msg='token is invalid', error_code=1002)
    r = {
        'scope': data[0]['scope'],
        'create_at': data[1]['iat'],
        'expire_in': data[1]['exp'],
        'uid': data[0]['uid']
    }
    return jsonify(r)


def generate_auth_token(uid, ac_type, scope=None,
                        expiration=7200):
    """生成令牌"""
    s = Serializer(current_app.config['SECRET_KEY'],
                   expires_in=expiration)
    return s.dumps({
        'uid': uid,
        'type': ac_type.value,
        'scope': scope
    })
